import * as obvm from '../../runtime/vm.mjs'

class WebSerialAPI {
    constructor() { }
    ports = [];
    scan(state) {
        if (!navigator.serial) {
            state.fsm.VM.Log('Web Serial API not support', 'sys', 6)
            state.fsm.PostMessage(state.fsm.VM.buildEventMessage("Serial_scanFinished", "", null, null));
            return;
        }
        navigator.serial.getPorts().then(p => {
            this.ports = p;
            state.fsm.PostMessage(state.fsm.VM.buildEventMessage("Serial_scanFinished", "", null, null));
        }).catch(e => {
            console.warn(e);
        });
    }
    getPorts() {
        let list = new obvm.OBList(Array.from(this.ports));
        return list;
    }
    requestPort(state) {
        navigator.serial.requestPort().then(p => {
            state.fsm.PostMessage(state.fsm.VM.buildEventMessage("Serial_selected", "SerialPort", p, null));
        }).catch(e => {
            state.fsm.VM.Log(e.message, 'sys', 6)
            console.warn(e);
        });
    }
    vendorId(port) {
        if (!port) {
            return 0;
        }
        return port.getInfo().usbVendorId || 0;
    }
    productId(port) {
        if (!port) {
            return 0;
        }
        return port.getInfo().usbProductId || 0;
    }
    open(port, baudRate, bufferSize, dataBits, flowControl, parity, stopBits, state) {
        if (!port) {
            return;
        }
        let options = { baudRate, bufferSize, dataBits, flowControl, parity, stopBits };
        port.open(options).then(() => {
            state.fsm.PostMessage(state.fsm.VM.buildEventMessage("Serial_opened", "SerialPort", port, null));
        }).catch((e) => {
            state.fsm.VM.Log(e.message, 'sys', 6)
            console.warn(e);
        });
    }
    write(port, data, state) {
        if (!port) {
            return;
        }
        let writer = port.writer;
        if (!writer) {
            writer = port.writable.getWriter();
            port.writer = writer;
        }
        let buffer = Uint8Array.from(data.c);
        writer.write(buffer).catch((e) => {
            state.fsm.VM.Log(e.message, 'sys', 6)
            console.warn(e);
        })
    }
    read(port, state) {
        let reader = port.reader;
        if (!reader) {
            reader = port.readable.getReader();
            port.reader = reader;
        }
        reader.read().then(r => {
            if (r.value) {
                port.readed = r.value;
                state.fsm.PostMessage(state.fsm.VM.buildEventMessage("Serial_readed", "SerialPort", port, null));
            } else if (r.done) {
                state.fsm.PostMessage(state.fsm.VM.buildEventMessage("Serial_readend", "SerialPort", port, null));
            }
        }).catch((e) => {
            state.fsm.VM.Log(e.message, 'sys', 6)
            console.warn(e);
        });
    }
    readed(port) {
        if (!port) {
            return;
        }
        let list = new obvm.OBList(Array.from(port.readed || []));
        port.readed = null;
        return list;
    }
    close(port, state) {
        if (!port) {
            return;
        }
        try {
            port.close();
        } catch (e) {
            console.warn(e);
            state.fsm.VM.Log(e.message, 'sys', 7);
        }
    }
    static install(script) {
        let api = new WebSerialAPI();
        script.InstallLib("WebSerialAPI", "WebSerialAPI", [
            script.NativeUtil.closureVoid(api.scan.bind(api),
                [], true),
            script.NativeUtil.closureVoid(api.requestPort.bind(api),
                [], true),
            script.NativeUtil.closureReturnValue(api.getPorts.bind(api), 'StructRegister',
                [], false),
            script.NativeUtil.closureReturnValue(api.vendorId.bind(api), 'LongRegister',
                ['NObjectRegister'], false),
            script.NativeUtil.closureReturnValue(api.productId.bind(api), 'LongRegister',
                ['NObjectRegister'], false),
            script.NativeUtil.closureVoid(api.open.bind(api),
                ['NObjectRegister', 'LongRegister',
                    'LongRegister', 'LongRegister',
                    'StringRegister', 'StringRegister', 'LongRegister'], true),
            script.NativeUtil.closureVoid(api.write.bind(api),
                ['NObjectRegister', 'StructRegister'], true),
            script.NativeUtil.closureVoid(api.read.bind(api),
                ['NObjectRegister'], true),
            script.NativeUtil.closureReturnValue(api.readed.bind(api), 'StructRegister',
                ['NObjectRegister'], true),
            script.NativeUtil.closureVoid(api.close.bind(api),
                ['NObjectRegister'], true),
        ]);
    }
}

export default WebSerialAPI;